---
title: "Adaptive Engine"
type: entity
created: 2026-04-18
updated: 2026-04-18
sources: ["raw/articles/06-reading-telemetry.md", "raw/notes/memory.md"]
tags: [service, adaptive-engine, fk-leveling, gpt-4o]
---

# Adaptive Engine

The Adaptive Engine is the service that re-levels any book page to a child's exact Flesch-Kincaid reading grade, making [[Pickatale]]'s entire library accessible at every child's level.

## Service Details

| Attribute | Value |
|---|---|
| Domain | adapt.readingtester.com |
| Server port | 3119 |
| Code location | `/home/ubuntu/adaptive-content/` |
| Database | `adaptive_content` on shared MySQL |
| Status | ✅ Live. GPT levelling works. Translation unavailable (no DeepL/Google keys). |

## What It Does

For every page the [[Reader App]] renders, the Adaptive Engine:

1. Receives the source text, `book_id`, `page_number`, and `target_fk_grade`
2. Checks the `leveled_text_cache` — if hit, returns immediately (<50ms)
3. On cache miss: calls GPT-4o to rewrite the text at the target FK level
4. Scores the result — retries once if deviation >0.5 grades
5. Stores in cache and returns leveled text

⚠️ **Non-Negotiable (Sig):** ALL content is adaptive. Every page of every book must pass through the Adaptive Engine before rendering.

## Core Endpoints

### POST /api/v1/level-page

Primary endpoint — called by Reader App on every page render.

**Body:**
```json
{
  "book_id": "14760-1",
  "page_number": 3,
  "source_text": "...",
  "target_fk_grade": 3.5,
  "learner_id": "uuid"
}
```

**Cache key:** `book_id + page_number + round(target_fk_grade, 1) + sha256(source_text)`

**Response:**
```json
{
  "leveled_text": "...",
  "actual_fk": 3.4,
  "from_cache": false
}
```

### POST /api/v1/adapt

More precise endpoint for internal pipelines (lesson book generation, testing):
- `target_fk_grade` is DECIMAL(4,2) — two decimal places
- Cache tolerance ±0.1 (stricter than level-page)
- Accepts `vocab_hints: string[]` — words to preserve in output

## FK Leveling Algorithm

```
targetFkLevel = child.reading_level + 0.5  (ZPD offset)
targetFkLevel = min(targetFkLevel, 5.5)    (cap)
```

The +0.5 Zone of Proximal Development offset puts text slightly above the child's current level — challenging enough to promote growth, accessible enough not to frustrate.

**FK formula:**

$$FK = 0.39 \times \left(\frac{\text{words}}{\text{sentences}}\right) + 11.8 \times \left(\frac{\text{syllables}}{\text{words}}\right) - 15.59$$

## Known Issues

⚠️ **Known Issue (2026-04-18):** FK scores sometimes unchanged in practice. Example: target 3.5 → actual FK 20.87. GPT-4o doesn't natively optimize for the FK formula.

Three remediation options under consideration:
1. Tighten the system prompt with explicit word/sentence length constraints
2. Stricter validation with up to 3× retries
3. Accept approximation (current default) and log deviations

See [[concepts/adaptive-content/FK Leveling]] for full analysis.

## Provider Configuration

| Provider | Status |
|---|---|
| GPT-4o | ✅ Active — handles leveling + translation in one call |
| DeepL | ❌ No API key |
| Google Translate | ❌ No API key |

Translation is architecturally planned but not deployable until keys are provisioned.

## Related Pages

- [[concepts/adaptive-content/index|Adaptive Content Engine]] — concept overview
- [[concepts/adaptive-content/FK Leveling]] — ZPD offset, API contract, known issue
- [[concepts/adaptive-content/Content Engine]] — full pipeline with caching diagram
- [[entities/Reader App]] — primary consumer
